#ifndef __LOG_H
#define __LOG_H

#include "../rtos/mutex.h"
#include <type_traits>


void print_log(const char *s, uint8_t len);

extern const char HEX_LIST[16];

template <typename IntType, uint8_t BASE = 10>
uint8_t num_len(IntType value) {
    uint8_t len = 1;
    while ( (value /= BASE) != 0 ) {
        len += 1;
    }
    return len;
}

template <typename IntType, uint8_t BASE = 10>
uint8_t num_to_str(char *buf, IntType value) {
    uint8_t len = num_len<IntType, BASE>(value);
    for (uint8_t i = 0; i < len; i ++) {
        buf[len - 1 - i] = HEX_LIST[ value % BASE ];
        value /= BASE;
    }
    return len;
}

uint8_t str_copy(char *buf, const char *str);

template <typename IntType, uint8_t BASE = 10>
uint8_t add_arg(char *buf, const char *name, IntType value) {
    uint8_t len_1 = str_copy(buf, name);
    buf[len_1] = '=';
    uint8_t len_3 = num_to_str(buf + len_1 + 1, value);
    buf[len_1 + 1 + len_3] = ' ';
    return len_1 + 1 + len_3 + 1;
}

class Log {

public:
    static constexpr uint32_t MAX_BUF_SIZE = 90;

private:
    template <typename T, typename... Ts>
    uint8_t append_arg(uint8_t index, const char *name, T var, Ts... vars) {
        uint8_t len = add_arg(m_buf + index, name, var);
        if constexpr (sizeof...(Ts) != 0) {
            return len + append_arg(index + len, vars...);
        } else {
            return len;
        }
    }

    template <typename T>
    uint8_t to_str(uint8_t index, T value) {
        if constexpr (std::is_same_v<T, const char *>) {
            return str_copy(m_buf + index, value);
        } else {
            return num_to_str(m_buf + index, value);
        }
    }

    template <typename T, typename... Ts>
    uint8_t append(uint8_t index, T value, Ts... ts) {
        uint8_t len = to_str(index, value);
        if constexpr (sizeof...(Ts) != 0) {
            return len + append(index + len, ts...);
        } else {
            return len;
        }
    }

public:
    void init() {
        m_mutex.init();
    }

    template <typename... Ts> 
    void print_args(const Ts&... ts) {
        AUTO_LOCK(m_mutex);
        uint8_t len = append_arg(0, ts...);
        print_log(m_buf, len);
    }

    template <typename... Ts>
    void print(Ts... ts) {
        AUTO_LOCK(m_mutex);
        uint8_t len = append(0, ts...);
        print_log(m_buf, len);
    }

private:
    rtos::Mutex m_mutex;
    char m_buf[MAX_BUF_SIZE];
};

extern Log __log;
#define LOG_INIT()  __log.init()

#define ARG(A)   #A, A
#define VAR_INFO1(a1) __log.print_args(ARG(a1))
#define VAR_INFO2(a1, a2)   __log.print_args(ARG(a1), ARG(a2))
#define VAR_INFO3(a1, a2, a3) __log.print_args(ARG(a1), ARG(a2), ARG(a3))
#define VAR_INFO4(a1, a2, a3, a4) __log.print_args(ARG(a1), ARG(a1), ARG(a3), ARG(a4))

#define print(...)   __log.print(__VA_ARGS__)

#define ASSERT(X)                                                              \
    {                                                                          \
        while (!(X)) {                                                          \
            print("assert fail:", __func__ " " __LINE__);                  \
            osDelay(1000);                                                     \
        }                                                                      \
    }

template <typename... Ts>
class ExecLogHelper {

public:
    ExecLogHelper(const char *fn) : m_func_name(fn) {
        m_tick = osKernelGetTickCount();
        print("开始执行:", m_func_name);
    }

    ~ExecLogHelper() {
        uint32_t duration = osKernelGetTickCount() - m_tick;
        print("执行完成:", m_func_name, " 耗时:", duration, "ms");
    }

private:
    const char *m_func_name;
    uint32_t m_tick;
};

#define EXEC_LOG()      ExecLogHelper __EXEC_INFO(__func__)

#endif
